package com.retrozelda.nyanimals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import android.graphics.Color;
import android.graphics.RectF;
import android.text.format.Time;
import android.text.method.DateTimeKeyListener;
import android.util.*;
import android.view.MotionEvent;

import com.retrozelda.nyanimals.CNyanimal.NyanimalStates;

public class CRoom extends INyanObject
{
	private static final String	TAG	= CRoom.class.getSimpleName();
	
	// class for sorting and collision checks
	class ActiveObjectCompareAndCollision implements Comparator<INyanObject>
	{
		@Override
		public int compare(INyanObject arg0, INyanObject arg1)
		{
			// NOTE: Dangerous casting - type unverified
			CRectangle left = (CRectangle)arg0;
			CRectangle right = (CRectangle)arg1;
			

			// check collision
			RectF collisionResult = arg0.CheckCollision(arg1);
			if(collisionResult != null)
			{
				// handle collision
				arg0.HandleCollision(arg1, collisionResult);
			}
			
			collisionResult = arg1.CheckCollision(arg0);
			if(collisionResult != null)
			{
				// handle collision
				arg1.HandleCollision(arg0, collisionResult);
			}
			

			// sort by priority
			if( left.GetPriority() > right.GetPriority())
			{
				return 1;
			}
			else if( left.GetPriority() < right.GetPriority())
			{
				return -1;
			}
			else
			{
				// same priority, sort by Y position
				if( left.getPosition()[1] > right.getPosition()[1])
				{
					return 1;
				}
				else if( left.getPosition()[1] < right.getPosition()[1])
				{
					return -1;
				}
				else
				{
					return 0;
				}
			}
			
		}
	}

	// stuff
	Random m_random;
	
	List<INyanObject> 			m_ActiveObjects;
	
	CNyanimal					m_Nyanimal;
	CBackdrop					m_BackGround;
	CGarbage					m_Garbage;

	CProgressBar				m_TiredBar;
	CProgressBar				m_HungerBar;
	
	CStatusScreen				m_StatusScreen;

	// action buttons
	CButton						m_ExitButton;
	CButton						m_FeedButton;
	CButton						m_StatusButton;

	// to draw text
	CBitmapFont					m_Text;

	// utilities
	int							screenWidth;
	int							screenHeight;
	boolean						m_shouldExit;
	NyanimalGLSurfaceView 		m_Game;
	
	// flags
	boolean m_bCreateFood;

	public void UpdateScreenData(int width, int height)
	{
		screenWidth = width;
		screenHeight = height;

		m_Nyanimal.UpdateScreenData(width, height);
	}

	public boolean ShouldExit()
	{
		return m_shouldExit;
	}
	
	public CRoom()
	{
		m_random = new Random(System.currentTimeMillis());
		
		m_ActiveObjects = new ArrayList<INyanObject>();
		
		m_Nyanimal = new CNyanimal();
		m_BackGround = new CBackdrop();
		m_Garbage = new CGarbage();
		m_StatusScreen = new CStatusScreen();

		m_TiredBar = new CProgressBar();
		m_HungerBar = new CProgressBar();

		m_Text = new CBitmapFont();

		m_FeedButton = new CButton();
		m_ExitButton = new CButton();
		m_StatusButton = new CButton();
		
		m_shouldExit = false;
		m_bCreateFood = false;
	}

	@Override
	public Object clone()
	{
		CRoom ret = null;
		try
		{
			ret = (CRoom)super.clone();

			ret.m_Nyanimal = (CNyanimal)m_Nyanimal.clone();
			ret.m_BackGround = (CBackdrop)m_BackGround.clone();
			//ret.m_StatusScreen = (CStatusScreen)m_StatusScreen.clone();
			// TODO: Clone food
			/*
			ret.m_TiredBar = (CProgressBar)m_TiredBar.clone();
			ret.m_HungerBar = (CProgressBar)m_HungerBar.clone();
			*/
			
			ret.m_Text = (CBitmapFont)m_Text.clone();

			ret.m_FeedButton = (CButton)m_FeedButton.clone();
			ret.m_ExitButton = (CButton)m_ExitButton.clone();
			ret.m_StatusButton = (CButton)m_StatusButton.clone();
		}
		catch(CloneNotSupportedException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return ret;
	}

	@Override
	public void Init(NyanimalGLSurfaceView game)
	{

		m_Game = game;
		Log.d(TAG, "Init Background");
		m_BackGround.Init(m_Game);
		
		Log.d(TAG, "Init Nyanimal");
		m_Nyanimal.Init(m_Game);
				
		Log.d(TAG, "Init Garbage");
		m_Garbage.Init(m_Game);

		Log.d(TAG, "Init Status Screen");
		m_StatusScreen.Init(game, m_Nyanimal);

		Log.d(TAG, "Init HUD bars");
		m_TiredBar.Init(game, false, R.drawable.energy_frames, R.drawable.energy_gradient, 5, 50, 256, 64, (int)m_Nyanimal.GetMeterMax(), (int)m_Nyanimal.GetTiredMeter());
		m_HungerBar.Init(game, false, R.drawable.hunger_frames, R.drawable.hunger_gradient, 5, 200, 256, 64, (int)m_Nyanimal.GetMeterMax(), (int)m_Nyanimal.GetHungerMeter());
		
		Log.d(TAG, "Set Positions");
		m_Nyanimal.SetPosition((int)(0.5f * m_Game.getWidth()), (int)(0.75f * m_Game.getHeight()));

		Log.d(TAG, "Init bitmap fonts");
		m_Text.Init(m_Game);
		m_Text.SetSize(24, 24);

		int nOffset = 5;
		Log.d(TAG, "Init Feed Button");
		int[] nButtonSize = new int[2];
		m_FeedButton.Init(m_Game, 0, 0, 64, 64, R.drawable.feed, R.drawable.feedpressed );
		nButtonSize = m_FeedButton.GetSize();
		m_FeedButton.SetPosition(nButtonSize[0] + nOffset, m_Game.getHeight() - nButtonSize[1] - nOffset);

		Log.d(TAG, "Init Exit Button");
		m_ExitButton.Init(m_Game, 0, 0, 64, 64, R.drawable.exitbutton, R.drawable.exitbuttonpressed );
		nButtonSize = m_ExitButton.GetSize();	
		m_ExitButton.SetPosition(m_Game.getWidth() - nButtonSize[0] - nOffset, m_Game.getHeight() - nButtonSize[1] - nOffset);	

		Log.d(TAG, "Init Stat Button");
		m_StatusButton.Init(m_Game, 0,0, 64, 64, R.drawable.statusbutton, R.drawable.statusbuttonpressed);
		nButtonSize = m_StatusButton.GetSize();
		m_StatusButton.SetPosition((nButtonSize[0] * 4) + nOffset, m_Game.getHeight() - nButtonSize[1] - nOffset);
		

		m_ActiveObjects.add(m_Nyanimal);
		m_ActiveObjects.add(m_Garbage);		
		
		Log.d(TAG, "Room init complete");
	}

	int nFPS = 0;
	int nCounter = 0;
	float fTime = 0.0f;
	@Override
	public void Update(float deltaTime)
	{
		fTime += deltaTime;
		nCounter++;
		if(fTime > 1.0f)
		{
			fTime = 0.0f;
			nFPS = nCounter;
			nCounter = 0;
		}
		
		if(m_bCreateFood == true)
		{
			CreateFood();
			m_bCreateFood = false;
		}
				

		m_BackGround.Update(deltaTime);
		m_StatusScreen.Update(deltaTime);


		m_TiredBar.SetCurrentValue((int)m_Nyanimal.GetTiredMeter());
		m_HungerBar.SetCurrentValue((int)m_Nyanimal.GetHungerMeter());
		m_TiredBar.Update(deltaTime);
		m_HungerBar.Update(deltaTime);
		
		/*
		// update all the displays
		int[] barPos = m_TiredBar.getPosition();
		m_Text.DrawText("Tired: " + m_TiredBar.GetPercent() + "%", barPos[0], barPos[1]);
		
		barPos = m_HungerBar.getPosition();
		m_Text.DrawText("Hunger: " + m_HungerBar.GetPercent() + "%", barPos[0], barPos[1]);
		
		m_Text.DrawText("FPS: " + nFPS, 10, 0);
		 */
		// update buttons
		m_FeedButton.Update(deltaTime);
		m_ExitButton.Update(deltaTime);
		m_StatusButton.Update(deltaTime);
		

		// update all the active objects
		for(int nObjIndex = 0; nObjIndex < m_ActiveObjects.size(); ++nObjIndex)
		{
			INyanObject curObj = m_ActiveObjects.get(nObjIndex);
			
			// remove if necessary
			if(curObj.GetObjectStatus() == ObjStatus.DELETE)
			{
				m_ActiveObjects.remove(nObjIndex);
				nObjIndex--;
			}
			else
			{
				if(curObj != null)
				{
					curObj.Update(deltaTime);	
				}
			}
			
		}


		// sort the active objects while checking collision
		Collections.sort(m_ActiveObjects, new ActiveObjectCompareAndCollision());
		
		/*
		// collision checks
		for(int nCollisionOuter = 0; nCollisionOuter < m_ActiveObjects.size() - 1; ++nCollisionOuter)
		{
			for(int nCollisionInner = nCollisionOuter + 1; nCollisionInner < m_ActiveObjects.size(); ++nCollisionInner)
			{
				INyanObject outer = m_ActiveObjects.get(nCollisionOuter);
				INyanObject inner = m_ActiveObjects.get(nCollisionInner);
				
				// check collision
				RectF collisionResult = outer.CheckCollision(inner);
				if(collisionResult != null)
				{
					// handle collision
					outer.HandleCollision(inner, collisionResult);
				}
			}
		}*/
	}
	
	@Override
	public void Draw(CArgumentGroup arg)
	{
		// draw all the background stuff
		m_BackGround.Draw(arg);
		
		// draw all the active objects
		for(int nObjIndex = 0; nObjIndex < m_ActiveObjects.size(); ++nObjIndex)
		{
			INyanObject curFood = m_ActiveObjects.get(nObjIndex);
			curFood.Draw(arg);			
		}
		
		// draw all the UI stuff
		m_TiredBar.Draw(arg);
		m_HungerBar.Draw(arg);
		m_FeedButton.Draw(arg);
		m_ExitButton.Draw(arg);
		m_StatusButton.Draw(arg);
		m_StatusScreen.Draw(arg);
		m_Text.Draw(arg);
	}
	
	public void CreateFood()
	{
		CFood newFood = new CFood();
		newFood.Init(m_Game);
		m_ActiveObjects.add(newFood);
		
		int nRandX = m_random.nextInt(screenWidth - 200) + 100;
		
		newFood.SetPosition(nRandX, 0);
	}

	public boolean HandleTouchEvent(MotionEvent event)
	{
		// touch information
		int posX = (int)event.getX();
		int posY = (int)event.getY();
		
		// handle all active objects
		HandleTouch(posX, posY, event.getAction());	
		
		// handle the room buttons
		// TODO: do this in the class with the reactions as callbacks
		switch (event.getAction())
		{
		case MotionEvent.ACTION_MOVE:
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_DOWN:


			// check if we want to feed
			int nFeedTouch = m_FeedButton.CheckTouch(posX, posY);
			int nExitTouch = m_ExitButton.CheckTouch(posX, posY);
			int nStatTouch = m_StatusButton.CheckTouch(posX, posY);
			
			if(event.getAction() == MotionEvent.ACTION_UP)
			{
				if(nFeedTouch >= 2)
				{
					m_bCreateFood = true;
					// m_Nyanimal.ChangeState(NyanimalStates.EATING);
					// Log.d(TAG, "Feeding via touch");
				}
				if(nExitTouch >= 2)
				{
					//android.os.Process.killProcess(android.os.Process.myPid());
					m_shouldExit = true;
					Log.d(TAG, "Exiting via touch");
					return false;
				}
				if(nStatTouch >= 2)
				{
					Log.d(TAG, "Stats Touched!");
					m_StatusScreen.ToggleVisibility();
				}
				m_FeedButton.SetTouchState(false);
				m_ExitButton.SetTouchState(false);
				m_StatusButton.SetTouchState(false);
			}

			break;
		}
		return true;
	}

	@Override
	public boolean HandleTouch(int nPosX, int nPosY, int nTouchAction) 
	{
		// handle all objects
		for(int nObjIndex = 0; nObjIndex < m_ActiveObjects.size(); ++nObjIndex)
		{
			INyanObject curObj = m_ActiveObjects.get(nObjIndex);
			boolean bBusy = curObj.HandleTouch(nPosX, nPosY, nTouchAction);	
			
			if(bBusy == true)
			{	
				// move this food to the "front"
				m_ActiveObjects.remove(curObj);
				m_ActiveObjects.add(curObj);
				break;
			}
		}
		return false;
	}

	@Override
	public Type GetType() 
	{
		// TODO Auto-generated method stub
		return Type.ROOM;
	}

	@Override
	public RectF CheckCollision(INyanObject inner) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void HandleCollision(INyanObject inner, RectF overlap) {
		// TODO Auto-generated method stub
		
	}
}
